
#include "aerProgram.hpp"
#include <glsw/glsw.h>



namespace {
  const unsigned int s_kBufferSize = 8*1024u;
  char s_buffer[s_kBufferSize]; //
}

namespace aer {

Program *Program::sCurrent = NULL;


bool Program::create( const ShaderType shaderType, const char* name)
{
  AER_ASSERT( glswGetError() == 0 );
  
  const GLchar *source = glswGetShader( name );

  if (!source)
  {
    fprintf( stderr, "Error : shader \"%s\" not found, check your directory.\n", name);
    return false;
  }

  m_id = glCreateShaderProgramv( shaderType, 1, (const GLchar**)&source);
  
  GLint status;
  glGetProgramiv( m_id, GL_LINK_STATUS, &status);
  
  if (status != GL_TRUE)
  {
    glGetProgramInfoLog( m_id, s_kBufferSize, NULL, s_buffer);
    fprintf( stderr, "%s\n", s_buffer);
    return false;
  }
  
  return true;
}

bool Program::addShader(const ShaderType shaderType, const char* name)
{
  AER_ASSERT( glswGetError() == 0 );
  
  
  const GLchar *source = glswGetShader( name );

  if (!source)
  {
    fprintf( stderr, "Error : shader \"%s\" not found, check your directory.\n", name);
    return false;
  }

  return addShaderSrc( shaderType, source, name);
}

bool Program::addShaderSrc( const ShaderType shaderType, const char* source, const char* name)
{
  GLuint shader = glCreateShader( shaderType );
  glShaderSource( shader, 1, (const GLchar**)&source, 0);
  glCompileShader( shader );

  GLint status = GL_TRUE;
  glGetShaderiv( shader, GL_COMPILE_STATUS, &status);

  if (status != GL_TRUE)
  {    
    glGetShaderInfoLog( shader, s_kBufferSize, NULL, s_buffer);
    fprintf( stderr, "%s :\n%s\n", name?name:"Unknown shader", s_buffer);
    return false;
  }
  
  // Attach & flag the shader for deletion
  glAttachShader( m_id, shader);
  glDeleteShader( shader );  
  
  return true;
}

bool Program::link()
{
  glLinkProgram( m_id );

  GLint status;
  glGetProgramiv( m_id, GL_LINK_STATUS, &status);
  
  if (status != GL_TRUE)
  {
    glGetProgramInfoLog( m_id, s_kBufferSize, NULL, s_buffer);
    fprintf( stderr, "%s\n", s_buffer);
    return false;
  }
  
  return true;
}

} // aer
